package com.h6.crm.service.Impl;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.h6.crm.entity.Brand;
import com.h6.crm.entity.Client;
import com.h6.crm.entity.Contract;
import com.h6.crm.entity.HrEmployee;
import com.h6.crm.entity.Project;
import com.h6.crm.entity.QuoteRecord;
import com.h6.crm.entity.SysUser;
import com.h6.crm.mapper.ContractMapper;
import com.h6.crm.service.AttachmentService;
import com.h6.crm.service.BrandService;
import com.h6.crm.service.ClientService;
import com.h6.crm.service.ContractService;
import com.h6.crm.service.HrEmployeeService;
import com.h6.crm.service.ProjectService;
import com.h6.crm.service.QuoteService;
import com.h6.crm.util.Constant;
import com.h6.crm.util.pojo.ResultCode;
import com.h6.crm.util.pojo.ServiceException;
import com.h6.crm.util.pojo.vo.QueryContractVO;
import com.h6.crm.util.pojo.vo.SaveContractByQuoteVO;
import com.h6.crm.util.pojo.vo.SaveContractVO;
import com.h6.crm.util.pojo.vo.UpdateContractStatusVO;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;

@Service
public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> implements ContractService {

    @Autowired
    ProjectService projectService;

    @Autowired
    ClientService clientService;

    @Autowired
    AttachmentService attachmentService;

    @Autowired
    HrEmployeeService employeeService;

    @Autowired
    QuoteService quoteService;

    @Autowired
    BrandService brandService;

    @Autowired
    ContractMapper contractMapper;

    @Override
    public Boolean saveContract(SaveContractVO contractVo, SysUser user) {
        Contract contract = new Contract();
        BeanUtils.copyProperties(contractVo, contract);
        Client client = clientService.getOne(new LambdaQueryWrapper<Client>()
                .eq(Client::getName, contractVo.getClientName()));

        Project project = projectService.getById(contractVo.getProjectId());
        if (ObjectUtil.isNull(project)) {
            throw new ServiceException("项目不存在");
        }
        // 合同编号
        Brand brand = brandService.getById(contractVo.getEntityId());
        if (ObjectUtil.isNull(brand)) {
            throw new ServiceException("商标不存在");
        }
        if (ObjectUtil.isNull(contractVo.getId())) {
            contract.setContractCode(generatorContractCode(brand.getShortening()));
        }
        if (ObjectUtil.isNull(client)) {
            client = new Client();
            client.setName(contractVo.getClientName());
            client.setClientCode(clientService.generatorClientCode());
            client.setBillType(15);
            client.setPayment("出运后");
            client.setPaymentMethodID(1);
            client.setCompanyId(1);
            client.setCurrencyID(1);
            client.setEnabled(false);
            client.setUpId(1);
            client.setEmplId(user.getEmplID());
            clientService.save(client);
        }
        if (ObjectUtil.isNull(contractVo.getSalesmanId())) {
            contract.setSalesmanId(project.getSalesmanId());
        }
        contract.setClientId(client.getId());
        saveOrUpdate(contract);
        try {
            attachmentService.dealFile(contractVo.getAttachmentPath(), contract.getId(), Constant.ATTACHMENT_CONTRACT,
                    null);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new ServiceException(ResultCode.ATTACHMENT_UPLOAD_FAILD);
        }
        return true;

    }

    @Override
    public IPage<Contract> queryContractList(QueryContractVO contractVo) {
        QueryWrapper<Contract> queryWrapper = new QueryWrapper<>();
        if (StrUtil.isNotBlank(contractVo.getClientName())) {
            List<Client> clientList = clientService.list(new LambdaQueryWrapper<Client>()
                    .eq(Client::getName, contractVo.getClientName()));
            if (clientList.isEmpty()) {
                return new Page<Contract>(-1, 10);
            }
            queryWrapper.in("ClientId", clientList.stream().map(Client::getId).collect(Collectors.toList()));
        }
        if (StrUtil.isNotBlank(contractVo.getProjectName())) {
            List<Project> projectList = projectService.list(new LambdaQueryWrapper<Project>()
                    .like(Project::getName, contractVo.getProjectName()));
            if (projectList.isEmpty()) {
                return new Page<Contract>(-1, 10);
            }
            queryWrapper.in("ProjectId", projectList.stream().map(Project::getId).collect(Collectors.toList()));
        }
        queryWrapper.eq(ObjectUtil.isNotNull(contractVo.getEntityId()), "EntityId", contractVo.getEntityId());
        queryWrapper.eq(ObjectUtil.isNotNull(contractVo.getSalesmanId()), "SalesmanId", contractVo.getSalesmanId());
        queryWrapper.like(StrUtil.isNotBlank(contractVo.getName()), "Name", contractVo.getName());
        queryWrapper.like(
                StrUtil.isNotBlank(contractVo.getContractStatus()), "ContractStatus", contractVo.getContractStatus());
        queryWrapper.like(
                StrUtil.isNotBlank(contractVo.getPaymentStatus()), "PaymentStatus", contractVo.getPaymentStatus());
        // 时间区间过滤
        queryWrapper.ge(ObjectUtil.isNotNull(contractVo.getStartDate()), "FORMAT(SigningDate, 'yyyy-MM-dd')",
                contractVo.getStartDate());
        queryWrapper.le(ObjectUtil.isNotNull(contractVo.getEndDate()), "FORMAT(SigningDate, 'yyyy-MM-dd')",
                contractVo.getEndDate());
        queryWrapper.orderByDesc("SigningDate").lambda().orderByAsc(Contract::getName);
        Page<Contract> contractPage = page(
                new Page<Contract>(contractVo.getPage(), contractVo.getPageSize()), queryWrapper);
        Map<Long, Brand> brandCache = new HashMap<>();
        Map<Long, Client> clientCache = new HashMap<>();
        Map<Long, Project> projectCache = new HashMap<>();
        Map<Long, HrEmployee> employeeCache = new HashMap<>();
        Brand brand;
        Client client;
        Project project;
        HrEmployee employee;
        List<Contract> contractListTemp = contractPage.getRecords();
        brandService.queryBrandList().forEach(b -> brandCache.put(b.getId(), b));
        for (Contract contract : contractListTemp) {
            brand = brandCache.get(contract.getEntityId());
            if (ObjectUtil.isNotNull(brand)) {
                contract.setEntity(brand.getName());
            }
            client = clientCache.get(contract.getClientId());
            if (ObjectUtil.isNull(client)) {
                client = clientService.getById(contract.getClientId());
                clientCache.put(contract.getClientId(), client);
                if (ObjectUtil.isNotNull(client)) {
                    contract.setClientName(client.getName());
                }
            } else {
                contract.setClientName(client.getName());
            }
            project = projectCache.get(contract.getProjectId());
            if (ObjectUtil.isNull(project)) {
                project = projectService.getById(contract.getProjectId());
                projectCache.put(contract.getProjectId(), project);
                if (ObjectUtil.isNotNull(project)) {
                    contract.setProjectName(project.getName());
                }
            } else {
                contract.setProjectName(project.getName());
            }
            employee = employeeCache.get(contract.getSalesmanId());
            if (ObjectUtil.isNull(employee)) {
                employee = employeeService.getById(contract.getSalesmanId());
                employeeCache.put(contract.getSalesmanId(), employee);
                if (ObjectUtil.isNotNull(employee)) {
                    contract.setSalesman(employee.getEmplName());
                }
            } else {
                contract.setSalesman(employee.getEmplName());
            }

        }
        contractPage.setRecords(contractListTemp);
        return contractPage;
    }

    @Override
    public Contract getContractDetailById(String contractId) {
        return contractMapper.getContractDetailById(contractId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveContractByQuote(SaveContractByQuoteVO contractVo, SysUser user) {
        QuoteRecord quote = quoteService.getById(contractVo.getQuoteRecordId());
        if (ObjectUtil.isNull(quote)) {
            throw new ServiceException("报价单不存在");
        }
        Project project = projectService.getById(quote.getProjectId());
        if (ObjectUtil.isNull(project)) {
            throw new ServiceException("项目不存在");
        }
        Brand brand = brandService.getById(quote.getEntityId());
        if (ObjectUtil.isNull(brand)) {
            throw new ServiceException("商标不存在");
        }
        BigDecimal amountTemp = ObjectUtil.isNotNull(
                project.getTotalAmount()) ? project.getTotalAmount() : BigDecimal.ZERO;
        project.setTotalAmount(amountTemp.add(quote.getAmount()));
        project.setQuoteAmount(quote.getAmount());
        // 自动成交
        quote.setQuoteStatus(Constant.QUOTE_STATUS2);
        projectService.updateById(project);
        quoteService.updateById(quote);
        Contract contract = new Contract();
        contract.setAmount(quote.getAmount());
        contract.setSalesmanId(quote.getBidderId());
        contract.setEntityId(quote.getEntityId());
        contract.setSigningDate(quote.getQuoteDate());
        contract.setProjectId(quote.getProjectId());
        contract.setClientId(project.getClientId());
        contract.setRemark(quote.getRemark());
        contract.setName(project.getName());
        contract.setContractStatus(Constant.CONTRACT_STATUS1);
        contract.setPaymentStatus(Constant.PAYMENT_STATUS1);
        contract.setContractCode(generatorContractCode(brand.getShortening()));
        return save(contract);
    }

    @Override
    public List<Contract> queryContractList(Long projectId) {
        return contractMapper.queryContractListByProjectId(projectId);
    }

    @Override
    public Boolean updateContractStatus(String contractId, UpdateContractStatusVO contractStatusVO) {
        Contract contract = getById(contractId);
        if (ObjectUtils.isNull(contract)) {
            throw new ServiceException(ResultCode.DATA_NOT_EXISTS);
        }
        if (StrUtil.isNotBlank(contractStatusVO.getContractStatus())) {
            contract.setContractStatus(contractStatusVO.getContractStatus());
        }
        if (StrUtil.isNotBlank(contractStatusVO.getPaymentStatus())) {
            contract.setPaymentStatus(contractStatusVO.getPaymentStatus());
        }
        return updateById(contract);
    }

    @Override
    public Map<String, String> calculateAmountOfperiod(QueryContractVO vo) {
        QueryWrapper<Contract> queryWrapper = new QueryWrapper<>();
        if (StrUtil.isNotBlank(vo.getClientName())) {
            List<Client> clientList = clientService.list(new LambdaQueryWrapper<Client>()
                    .eq(Client::getName, vo.getClientName()));
            if (clientList.isEmpty()) {
                return new HashMap<String, String>(2) {
                    {
                        put("total", "0.00");
                    }
                };
            }
            queryWrapper.in("ClientId", clientList.stream().map(Client::getId).collect(Collectors.toList()));
        }
        if (StrUtil.isNotBlank(vo.getProjectName())) {
            List<Project> projectList = projectService.list(new LambdaQueryWrapper<Project>()
                    .like(Project::getName, vo.getProjectName()));
            if (projectList.isEmpty()) {
                return new HashMap<String, String>(2) {
                    {
                        put("total", "0.00");
                    }
                };
            }
            queryWrapper.in("ProjectId", projectList.stream().map(Project::getId).collect(Collectors.toList()));
        }
        queryWrapper.eq(ObjectUtil.isNotNull(vo.getEntityId()), "EntityId", vo.getEntityId());
        queryWrapper.eq(ObjectUtil.isNotNull(vo.getSalesmanId()), "SalesmanId", vo.getSalesmanId());
        queryWrapper.like(StrUtil.isNotBlank(vo.getName()), "Name", vo.getName());
        queryWrapper.like(StrUtil.isNotBlank(vo.getContractStatus()), "ContractStatus", vo.getContractStatus());
        queryWrapper.like(StrUtil.isNotBlank(vo.getPaymentStatus()), "PaymentStatus", vo.getPaymentStatus());
        // 时间区间过滤
        queryWrapper.ge(ObjectUtil.isNotNull(vo.getStartDate()), "FORMAT(SigningDate,'yyyy-MM-dd')", vo.getStartDate());
        queryWrapper.le(ObjectUtil.isNotNull(vo.getEndDate()), "FORMAT(SigningDate,'yyyy-MM-dd')", vo.getEndDate());
        BigDecimal total = list(queryWrapper).stream().map(
                Contract::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        return new HashMap<String, String>(2) {
            {
                put("total", String.valueOf(total));
            }
        };
    }

    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public Boolean removeByIdAndUpdateProject(String contractId) {
        Contract contract = getById(contractId);
        if (ObjectUtil.isNull(contract)) {
            throw new ServiceException(ResultCode.DATA_NOT_EXISTS);
        }
        Project project = projectService.getById(contract.getProjectId());
        if (ObjectUtil.isNotNull(project)) {
            BigDecimal amountTemp = project.getTotalAmount();
            amountTemp = amountTemp.subtract(contract.getAmount());
            if (BigDecimal.ZERO.compareTo(amountTemp) > 0) {
                amountTemp = BigDecimal.ZERO;
            }
            project.setTotalAmount(amountTemp);
            if (!removeById(contractId)) {
                throw new ServiceException("删除合同失败，请稍后再试");
            }
            return projectService.updateById(project);
        } else {
            return removeById(contractId);
        }
    }

    private synchronized String generatorContractCode(String brandShortening) {
        return brandShortening + new SimpleDateFormat("yyyyMMdd").format(new Date())
                + String.format("%03d", contractMapper.countByBrand(brandShortening) + 1);
    }

}
